<template>
  <div class="toolbar-column-setting">
    <el-popover
      placement="bottom"
      popper-class="columns-setting-popover"
      :width="200"
      :show-arrow="false"
      trigger="click"
    >
      <div class="column-setting">
        <div class="column-setting-title">
          <span class="label">列展示</span>
          <el-button type="primary" link @click="reset">重置</el-button>
        </div>
        <el-divider />
        <el-scrollbar class="column-setting-content" max-height="310px">
          <Draggable v-model="draggableList" handle=".mover" item-key="prop" animation="300">
            <template #item="{ element: item }">
              <div class="column-setting-item" v-if="item.type !== 'selection'">
                <div class="column-handle">
                  <i class="icon mover">
                    <Icon icon="ant-design:drag-outlined" />
                  </i>
                  <el-checkbox v-model="item.checked" :name="item.prop" @change="checkChange(item)">
                  </el-checkbox>
                  <el-text line-clamp="1"> {{ item.label }} </el-text>
                </div>
                <div class="column-fixed">
                  <el-tooltip placement="top" content="固定在左侧">
                    <i
                      class="icon"
                      :class="{ active: item.fixed === 'left' }"
                      @click="handleFixed(item, 'left')"
                    >
                      <Icon icon="ant-design:vertical-right-outlined" />
                    </i>
                  </el-tooltip>
                  <el-tooltip placement="top" content="固定在右侧">
                    <i
                      class="icon"
                      :class="{ active: item.fixed === 'right' }"
                      @click="handleFixed(item, 'right')"
                    >
                      <Icon icon="ant-design:vertical-left-outlined" />
                    </i>
                  </el-tooltip>
                </div>
              </div>
            </template>
          </Draggable>
        </el-scrollbar>
      </div>
      <template #reference>
        <slot />
      </template>
    </el-popover>
  </div>
</template>

<script setup>
import { computed, ref } from 'vue'
import { Icon } from '@iconify/vue'
import Draggable from 'vuedraggable'
import { isEmpty } from '@/utils/util.js'

const { columns } = defineProps({
  columns: { type: Array, default: () => [] }, // 表格列
})
const setList = ref([]) // 列设置列表
const setSort = {} // 列设置排序
let initValue = [] // 初始列设置
const initSort = {} // 列设置排序

const draggableList = computed({
  get() {
    return setList.value
  },
  set(val) {
    setList.value = val
    //更新setSort的排序值
    const tmpSorts = Object.values(setSort).sort((a, b) => a - b)
    for (let i = 0; i < setList.value.length; i++) {
      const item = setList.value[i]
      const key = getSortKey(item)
      setSort[key] = tmpSorts[i]
    }
    handleSort()
  },
})

const cloneColumns = (list) => {
  return list.map((d) => ({ ...d }))
}

const getSortKey = (item) => {
  return item.prop || item.type
}

const isSet = ({ prop, type }) => {
  const types = ['selection', 'index', 'expand']
  return !isEmpty(prop) && !types.includes(type)
}

const updateSetList = () => {
  if (!columns || !Array.isArray(columns)) return
  // 缓存结果避免重复计算
  setList.value = columns
    .filter((item) => item && isSet(item))
    .map(({ type, prop, label, fixed, hide }) => ({
      type,
      prop,
      label,
      fixed,
      checked: hide !== true,
    }))
}

// 初始化值
initValue = cloneColumns(columns)

const init = () => {
  updateSetList()
  columns.forEach((item, index) => {
    const sortKey = getSortKey(item)
    initSort[sortKey] = index
    if (isSet(item)) {
      setSort[sortKey] = index
    }
  })
}

init()

// =========================== 处理 =======================

const handleSort = () => {
  // eslint-disable-next-line vue/no-mutating-props
  columns.sort((a, b) => {
    const aKey = getSortKey(a)
    const bKey = getSortKey(b)
    return (setSort[aKey] || initSort[aKey]) - (setSort[bKey] || initSort[bKey])
  })
}

const handleFixed = (data, fixed) => {
  if (data.fixed === fixed) {
    data.fixed = false
  } else {
    data.fixed = fixed
  }
  const item = columns.find((item) => item.prop === data.prop)
  if (item) {
    if (fixed === item.fixed) {
      item.fixed = false
    } else {
      item.fixed = fixed
    }
  }
}

const checkChange = ({ checked, prop }) => {
  for (let i = 0; i < columns.length; i++) {
    const item = columns[i]
    if (item.prop === prop) {
      item.hide = !checked
      break
    }
  }
}

const reset = () => {
  const cloned = cloneColumns(initValue)
  // 清空原数组
  // eslint-disable-next-line vue/no-mutating-props
  columns.splice(0)
  // 添加新元素
  // eslint-disable-next-line vue/no-mutating-props
  columns.push(...cloned)
  init()
}
</script>

<style lang="scss">
.toolbar-column-setting {
  display: inline-flex;
}
.columns-setting-popover.el-popover {
  padding: 0;
  .column-setting {
    .column-setting-title {
      padding: 12px 8px 0 12px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      .label {
        color: var(--el-text-color-primary);
        letter-spacing: 1px;
      }
      .el-button {
        padding: 0;
        height: auto;
      }
    }
    .el-divider {
      margin: 8px 0;
    }
    .column-setting-content {
      margin-bottom: 8px;
      .column-setting-item {
        padding: 7px 12px;
        align-items: center;
        display: flex;
        .icon {
          font-size: 15px;
        }
        .column-handle {
          flex: 1;
          display: flex;
          .mover {
            cursor: move;
            margin-right: 8px;
            font-size: 16px;
          }
          .el-checkbox {
            height: auto;
            margin-right: 5px;
          }
        }
        .column-fixed {
          flex-shrink: 0;
          display: flex;
          margin-left: 3px;
          .icon {
            cursor: pointer;
            &.active {
              color: var(--el-color-primary);
            }
          }
        }
      }
    }
  }
}
</style>
